package com.dkts.oil.test;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;

import java.io.*;
import java.util.*;

public class GeoJsonGeneratorV3 {

    public static void main(String[] args) throws Exception {
        File csvFile = new File("C:\\Users\\heyou\\Documents\\WeChat Files\\wxid_86da35bc9zvi21\\FileStorage\\File\\2025-05\\c9a6717b7d2f5293cf7cd2ed05a0494c_2e2437ef9cd58c0d39af05569deeb4be_8.csv");
        Reader reader = new FileReader(csvFile);

        CSVParser parser = CSVFormat.DEFAULT
                .withFirstRecordAsHeader()
                .parse(reader);

        Map<String, Trajectory> trajectories = new HashMap<>();
        for (CSVRecord record : parser) {
            String mmsi = record.get("mmsi");
            if (!trajectories.containsKey(mmsi)) {
                trajectories.put(mmsi, new Trajectory(mmsi));
            }
            Trajectory traj = trajectories.get(mmsi);
            traj.addPoint(Double.parseDouble(record.get("lon")), Double.parseDouble(record.get("lat")));
        }

        List<Trajectory> allTrajectories = new ArrayList<>(trajectories.values());

        // 设置相似度阈值，这里我们设定为 50
        double similarityThreshold = 50.0;
        List<List<Trajectory>> groupedTrajectories = groupSimilar(allTrajectories, similarityThreshold);

        // 对每个分组输出一个 GeoJSON 文件
        ObjectMapper mapper = new ObjectMapper();
        for (int i = 0; i < groupedTrajectories.size(); i++) {
            List<Trajectory> group = groupedTrajectories.get(i);
            ObjectNode featureCollection = mapper.createObjectNode();
            featureCollection.put("type", "FeatureCollection");
            ArrayNode features = mapper.createArrayNode();

            for (Trajectory trajectory : group) {
                ObjectNode feature = mapper.createObjectNode();
                feature.put("type", "Feature");

                // 构建 LineString
                ObjectNode geometry = mapper.createObjectNode();
                geometry.put("type", "LineString");
                ArrayNode coordinates = mapper.createArrayNode();
                for (double[] point : trajectory.points) {
                    ArrayNode coord = mapper.createArrayNode();
                    coord.add(point[0]);
                    coord.add(point[1]);
                    coordinates.add(coord);
                }
                geometry.set("coordinates", coordinates);
                feature.set("geometry", geometry);

                // 属性信息
                ObjectNode properties = mapper.createObjectNode();
                properties.put("mmsi", trajectory.mmsi);
                feature.set("properties", properties);

                features.add(feature);
            }

            featureCollection.set("features", features);

            // 输出为 GeoJSON 文件
            FileWriter writer = new FileWriter("group_" + (i + 1) + "_geojson_output.geojson");
            mapper.writerWithDefaultPrettyPrinter().writeValue(writer, featureCollection);
            System.out.println("GeoJSON 文件已生成：group_" + (i + 1) + "_geojson_output.geojson");
        }
    }

    public static List<List<Trajectory>> groupSimilar(List<Trajectory> all, double threshold) {
        List<List<Trajectory>> groups = new ArrayList<>();
        Set<String> visited = new HashSet<>();

        for (Trajectory t1 : all) {
            if (visited.contains(t1.mmsi)) continue;
            List<Trajectory> group = new ArrayList<>();
            group.add(t1);
            visited.add(t1.mmsi);

            for (Trajectory t2 : all) {
                if (visited.contains(t2.mmsi)) continue;
                double dist = DTWSimilarity.calculate(t1.points, t2.points);
                if (dist < threshold) {
                    group.add(t2);
                    visited.add(t2.mmsi);
                }
            }
            groups.add(group);
        }
        return groups;
    }

    public static class Trajectory {
        public String mmsi;
        public List<double[]> points;

        public Trajectory(String mmsi) {
            this.mmsi = mmsi;
            this.points = new ArrayList<>();
        }

        public void addPoint(double lon, double lat) {
            points.add(new double[]{lon, lat});
        }
    }

    public static class DTWSimilarity {
        public static double calculate(List<double[]> a, List<double[]> b) {
            int n = a.size();
            int m = b.size();
            double[][] dp = new double[n][m];

            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    double dist = distance(a.get(i), b.get(j));
                    if (i == 0 && j == 0) dp[i][j] = dist;
                    else if (i == 0) dp[i][j] = dist + dp[i][j - 1];
                    else if (j == 0) dp[i][j] = dist + dp[i - 1][j];
                    else dp[i][j] = dist + Math.min(dp[i - 1][j], Math.min(dp[i][j - 1], dp[i - 1][j - 1]));
                }
            }
            return dp[n - 1][m - 1];
        }

        private static double distance(double[] p1, double[] p2) {
            return Math.sqrt(Math.pow(p1[0] - p2[0], 2) + Math.pow(p1[1] - p2[1], 2));
        }
    }
}
